﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using iNet.Tasks;

namespace iNet.Media.Imaging
{
	/// <summary>
	/// ICO 影像解碼工作。
	/// </summary>
	public class IcoImageDecodeTask : ImageDecodeTask, IComparer<BitmapSource>
	{
		#region 建構子
		/// <summary>
		/// 初始化新的 IcoImageDecodeTask 執行個體。
		/// </summary>
		public IcoImageDecodeTask()
			: base(ImageFormats.Ico)
		{ }
		/// <summary>
		/// 初始化新的 IcoImageDecodeTask 執行個體。
		/// </summary>
		/// <param name="source">影像儲存來源。</param>
		public IcoImageDecodeTask(MediaStorage source)
			: base(ImageFormats.Ico, source, 0, 0)
		{ }
		#endregion
		#region Decode
		/// <summary>
		/// 解碼影像。
		/// </summary>
		/// <param name="version">工作版本。</param>
		/// <param name="source">影像儲存來源。</param>
		/// <param name="mediaDecodeReqs">媒體解碼請求。</param>
		/// <param name="imageDecodeReqs">影像解碼請求。</param>
		/// <returns>True 表示解碼完成，False 表示解碼失敗。</returns>
		protected override bool Decode(TaskVersion version, MediaStorage source, MediaDecodeRequests mediaDecodeReqs, ImageDecodeRequests imageDecodeReqs)
		{
			//確認參數
			if (mediaDecodeReqs == 0 && imageDecodeReqs == 0)
				return true;

			//取得參數
			int? decodeWidth = this.DecodePixelWidth;
			int? decodeHeight = this.DecodePixelHeight;
			bool maintainAspectRatio = this.MaintainAspectRatio;

			//解碼影像
			bool decodeImages = ((imageDecodeReqs & Imaging.ImageDecodeRequests.DecodeImage) != 0);
			bool decodeSize = ((imageDecodeReqs & Imaging.ImageDecodeRequests.DecodePixelSize) != 0);
			bool decodeThumbnail = ((mediaDecodeReqs & Media.MediaDecodeRequests.DecodeThumbnailImage) != 0);
			if (decodeImages || decodeSize || decodeThumbnail)
			{
				//取得資料流
				Stream stream;
				if (!this.GetMediaStorageStream(version, source, 50, out stream))
					throw new MediaDecodeFailedException(MediaDecodeFailedReason.CannotAccessStream);

				//取得影像大小
				try
				{
					//儲存資料流位置
					long startPosition = stream.Position;

					//確認標頭
					BitConverter bitConverter = BitConverter.LittleEndian;
					byte[] buffer4 = new byte[4];
					if (stream.Read(buffer4, 0, 4) < 4)
						throw new MediaDecodeFailedException(MediaDecodeFailedReason.InvalidFormat);
					if (buffer4[0] != 0 || buffer4[1] != 0)
						throw new MediaDecodeFailedException(MediaDecodeFailedReason.InvalidFormat);
					int imageType = bitConverter.ToUInt16(buffer4, 2);
					if (imageType != 1 && imageType != 2)
						throw new MediaDecodeFailedException(MediaDecodeFailedReason.InvalidFormat);

					//取得影像個數
					if (stream.Read(buffer4, 0, 2) < 2)
						throw new MediaDecodeFailedException(MediaDecodeFailedReason.InvalidFormat);
					int imageCount = bitConverter.ToUInt16(buffer4);

					//讀取影像大小
					HashSet<Size<int>> imageSizes = new HashSet<Size<int>>();
					byte[] buffer16 = new byte[16];
					for (int i = imageCount; i > 0; --i)
					{
						if (stream.Read(buffer16, 0, 16) < 16)
							throw new MediaDecodeFailedException(MediaDecodeFailedReason.InvalidFormat);
						int width = (buffer16[0] > 0 ? buffer16[0] : 256);
						int height = (buffer16[1] > 0 ? buffer16[1] : 256);
						imageSizes.Add(new Size<int>(width, height));
					}

					//儲存影像大小
					if (decodeSize)
					{
						int maxWidth = 0;
						int maxHeight = 0;
						foreach (Size<int> size in imageSizes)
						{
							int width = size.Width;
							int height = size.Height;
							if (width > maxWidth && height > maxHeight)
							{
								maxWidth = width;
								maxHeight = height;
							}
						}
						if (maxWidth > 0)
							this.SetDecodedPixelSize(version, new Size<int>(maxWidth, maxHeight));
					}

					//中斷確認
					if (this.IsCanceling)
						return true;

					//恢復資料流位置
					stream.Position = startPosition;

					//解碼影像
					if (decodeImages || decodeThumbnail)
					{
						//建立解碼器
						BitmapCreateOptions createOptions = BitmapCreateOptions.None;
						if (this.IgnoreColorProfile)
							createOptions |= BitmapCreateOptions.IgnoreColorProfile;
						if (this.PreservePixelFormat)
							createOptions |= BitmapCreateOptions.PreservePixelFormat;
						IconBitmapDecoder decoder = new IconBitmapDecoder(stream, createOptions, BitmapCacheOption.OnLoad);

						//解碼影像
						List<BitmapSource> images = new List<BitmapSource>();
						foreach (BitmapFrame frame in decoder.Frames)
						{
							int index = images.BinarySearch(frame, this);
							images.Insert(index < 0 ? ~index : index, frame);
							if (this.IsCanceling)
								return true;
						}

						//儲存縮圖
						if (decodeThumbnail && images.Count > 0)
						{
							images[0].Freeze();
							this.SetDecodedThumbnailImage(version, new BitmapImage(images[0]));
						}

						//調整影像大小
						if (decodeWidth != null || decodeHeight != null)
						{
							BitmapSource frame = null;
							for (int i = images.Count - 1; i >= 0; --i)
							{
								BitmapSource candFrame = images[i];
								if (decodeWidth != null && decodeWidth.Value <= candFrame.PixelWidth)
								{
									frame = candFrame;
									break;
								}
								if (decodeHeight != null && decodeHeight.Value <= candFrame.PixelHeight)
								{
									frame = candFrame;
									break;
								}
							}
							if (frame != null)
							{
								if (decodeHeight == null)
								{
									if (maintainAspectRatio)
										decodeHeight = (decodeWidth * (frame.PixelHeight / frame.PixelWidth));
									else
										decodeHeight = frame.PixelHeight;
								}
								else if (decodeWidth == null)
								{
									if (maintainAspectRatio)
										decodeWidth = (decodeHeight * (frame.PixelWidth / frame.PixelHeight));
									else
										decodeWidth = frame.PixelWidth;
								}
								if (maintainAspectRatio)
								{
									double scale = Math.Min(decodeWidth.Value / (double)frame.PixelWidth, decodeHeight.Value / (double)frame.PixelHeight);
									frame = new TransformedBitmap(frame, new ScaleTransform(scale, scale));
								}
								else
								{
									double scaleX = (decodeWidth.Value / (double)frame.PixelWidth);
									double scaleY = (decodeHeight.Value / (double)frame.PixelHeight);
									frame = new TransformedBitmap(frame, new ScaleTransform(scaleX, scaleY));
								}
								if (!frame.Is96Dpi())
									frame = ImageUtility.CopyBitmap(frame, 96, 96);
								images.Clear();
								images.Add(frame);
							}
							else if (images.Count > 1)
								images.RemoveRange(1, images.Count - 1);
						}

						//建立唯讀點陣圖
						foreach (BitmapSource image in images)
							image.Freeze();

						//儲存解碼的影像
						if (decodeImages && images.Count > 0)
						{
							List<IImage> imageList = new List<IImage>();
							for (int i = images.Count - 1; i >= 0; --i)
								imageList.Add(new BitmapImage(images[i]));
							if (images.Count > 1)
								this.SetDecodedImage(version, new MultiImage(imageList, null, source, ImageFormats.Ico, true));
							else
								this.SetDecodedImage(version, imageList[0]);
						}
					}
				}
				catch (Exception ex)
				{
					throw new MediaDecodeFailedException(MediaDecodeFailedReason.InvalidFormat, ex);
				}
				finally
				{
					this.ReleaseMediaStorageStream(version, source, stream);
				}
			}

			//完成
			return true;
		}
		#endregion
		#region IComparer<BitmapSource>.Compare
		int IComparer<BitmapSource>.Compare(BitmapSource x, BitmapSource y)
		{
			if (x.PixelWidth < y.PixelWidth)
				return 1;
			if (x.PixelWidth > y.PixelWidth)
				return -1;
			if (x.Format.BitsPerPixel < y.Format.BitsPerPixel)
				return 1;
			if (x.Format.BitsPerPixel > y.Format.BitsPerPixel)
				return -1;
			return 0;
		}
		#endregion
	}
}
